#ifndef ETL_DETERMINANT_HPP
# define ETL_DETERMINANT_HPP
# pragma once

#include "matrix.h"

//////////////////////////////////////////////////////////////////////////////
template <class T>
inline T determinant(::etl::matrix<T, 1, 1> const& m) noexcept
{
  return m(0, 0);
}

//////////////////////////////////////////////////////////////////////////////
template <class T>
inline T determinant(::etl::matrix<T, 2, 2> const& m) noexcept
{
  return
    m(0, 0) * m(1, 1) -
    m(0, 1) * m(1, 0);
}

//////////////////////////////////////////////////////////////////////////////
template <class T>
inline T determinant(::etl::matrix<T, 3, 3> const& m) noexcept
{
  return
    m(0, 0) * m(1, 1) * m(2, 2) +
    m(0, 1) * m(1, 2) * m(2, 0) +
    m(0, 2) * m(1, 0) * m(2, 1) -
    m(0, 0) * m(1, 2) * m(2, 1) -
    m(0, 1) * m(1, 0) * m(2, 2) -
    m(0, 2) * m(1, 1) * m(2, 0);
}

//////////////////////////////////////////////////////////////////////////////
template <class T>
inline T determinant(::etl::matrix<T, 4, 4> const& m) noexcept
{
  return
    m(0, 3) * m(1, 2) * m(2, 1) * m(3, 0) -
    m(0, 2) * m(1, 3) * m(2, 1) * m(3, 0) - 
    m(0, 3) * m(1, 1) * m(2, 2) * m(3, 0) +
    m(0, 1) * m(1, 3) * m(2, 2) * m(3, 0) +
    m(0, 2) * m(1, 1) * m(2, 3) * m(3, 0) -
    m(0, 1) * m(1, 2) * m(2, 3) * m(3, 0) -
    m(0, 3) * m(1, 2) * m(2, 0) * m(3, 1) +
    m(0, 2) * m(1, 3) * m(2, 0) * m(3, 1) +
    m(0, 3) * m(1, 0) * m(2, 2) * m(3, 1) -
    m(0, 0) * m(1, 3) * m(2, 2) * m(3, 1) -
    m(0, 2) * m(1, 0) * m(2, 3) * m(3, 1) +
    m(0, 0) * m(1, 2) * m(2, 3) * m(3, 1) +
    m(0, 3) * m(1, 1) * m(2, 0) * m(3, 2) -
    m(0, 1) * m(1, 3) * m(2, 0) * m(3, 2) -
    m(0, 3) * m(1, 0) * m(2, 1) * m(3, 2) +
    m(0, 0) * m(1, 3) * m(2, 1) * m(3, 2) +
    m(0, 1) * m(1, 0) * m(2, 3) * m(3, 2) -
    m(0, 0) * m(1, 1) * m(2, 3) * m(3, 2) -
    m(0, 2) * m(1, 1) * m(2, 0) * m(3, 3) +
    m(0, 1) * m(1, 2) * m(2, 0) * m(3, 3) +
    m(0, 2) * m(1, 0) * m(2, 1) * m(3, 3) -
    m(0, 0) * m(1, 2) * m(2, 1) * m(3, 3) -
    m(0, 1) * m(1, 0) * m(2, 2) * m(3, 3) +
    m(0, 0) * m(1, 1) * m(2, 2) * m(3, 3);
}

#endif // ETL_DETERMINANT_HPP
